package server;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import java.util.Random;
import java.io.File;
import java.io.IOException;
import java.io.FileOutputStream;
import java.io.DataOutputStream;

public class ConfigurationManagerTest extends TestCase {

    final String testConfigFilename = "/tmp/cmtest.config";

    private static RandomUtils randomUtils = new RandomUtils();
    private static Random random = new Random();

	public ConfigurationManagerTest(String name) {
		super(name);
	}

	protected void setUp() {
        File file = new File(testConfigFilename);
        file.delete();
    }

	protected void tearDown() {
        File file = new File(testConfigFilename);
        file.delete();
    }

    // Test that when creating a new ConfigurationManager, the default values
    // are used.
    public void testDefaults() 
        throws CorruptConfigurationFileException, FirewallException {

        ConfigurationManager cm = new ConfigurationManager(testConfigFilename);

        assertEquals(cm.getIsFirewallOn(), cm.isFirewallOnDefault);
        assertEquals(cm.getIsLogActive(), cm.isLogActiveDefault);
        assertEquals(cm.getActiveRuleset(), cm.activeRulesetDefault);
        assertEquals(cm.getDBIP(), cm.dbIPDefault);
        assertEquals(cm.getDBName(), cm.dbNameDefault);
        assertEquals(cm.getDBUser(), cm.dbUserDefault);
        assertEquals(cm.getDBPassword(), cm.dbPasswordDefault);
    }

    // Test that the CM correctly remembers values, even if it's destructed
    // and reinitialized.
    public void testPersistence() 
        throws CorruptConfigurationFileException, FirewallException {

        ConfigurationManager cm = new ConfigurationManager(testConfigFilename);

        boolean currentIsFirewallOn = cm.isFirewallOnDefault;
        boolean currentIsLogActive = cm.isLogActiveDefault;
        String currentActiveRuleset = cm.activeRulesetDefault;
        String currentDBIP = cm.dbIPDefault;
        String currentDBName = cm.dbNameDefault;
        String currentDBUser = cm.dbUserDefault;
        String currentDBPassword = cm.dbPasswordDefault;

        for (int i = 0; i < 300; ++i) {
            // Pick value to change
            int value = random.nextInt(7);
            switch (value) {
                case 0: 
                    currentIsFirewallOn = random.nextBoolean();
                    cm.setIsFirewallOn(currentIsFirewallOn);
                    break;
                case 1: 
                    currentIsLogActive = random.nextBoolean();
                    cm.setIsLogActive(currentIsLogActive);
                    break;
                case 2: 
                    currentActiveRuleset = 
                        randomUtils.getRandomString(5 + random.nextInt(10));
                    cm.setActiveRuleset(currentActiveRuleset);
                    break;
                case 3: 
                    currentDBIP = 
                        randomUtils.getRandomString(5 + random.nextInt(10));
                    cm.setDBIP(currentDBIP);
                    break;
                case 4: 
                    currentDBName = 
                        randomUtils.getRandomString(5 + random.nextInt(10));
                    cm.setDBName(currentDBName);
                    break;
                case 5: 
                    currentDBUser = 
                        randomUtils.getRandomString(5 + random.nextInt(10));
                    cm.setDBUser(currentDBUser);
                    break;
                case 6: 
                    currentDBPassword = 
                        randomUtils.getRandomString(5 + random.nextInt(10));
                    cm.setDBPassword(currentDBPassword);
                    break;
            }

            assertEquals(currentIsFirewallOn, cm.getIsFirewallOn());
            assertEquals(currentIsLogActive, cm.getIsLogActive());
            assertEquals(currentActiveRuleset, cm.getActiveRuleset());
            assertEquals(currentDBIP, cm.getDBIP());
            assertEquals(currentDBName, cm.getDBName());
            assertEquals(currentDBUser, cm.getDBUser());
            assertEquals(currentDBPassword, cm.getDBPassword());
        }

        for (int i = 0; i < 300; ++i) {
            cm = new ConfigurationManager(testConfigFilename);

            // Pick value to change
            int value = random.nextInt(7);
            switch (value) {
                case 0: 
                    currentIsFirewallOn = random.nextBoolean();
                    cm.setIsFirewallOn(currentIsFirewallOn);
                    break;
                case 1: 
                    currentIsLogActive = random.nextBoolean();
                    cm.setIsLogActive(currentIsLogActive);
                    break;
                case 2: 
                    currentActiveRuleset = 
                        randomUtils.getRandomString(5 + random.nextInt(10));
                    cm.setActiveRuleset(currentActiveRuleset);
                    break;
                case 3: 
                    currentDBIP = 
                        randomUtils.getRandomString(5 + random.nextInt(10));
                    cm.setDBIP(currentDBIP);
                    break;
                case 4: 
                    currentDBName = 
                        randomUtils.getRandomString(5 + random.nextInt(10));
                    cm.setDBName(currentDBName);
                    break;
                case 5: 
                    currentDBUser = 
                        randomUtils.getRandomString(5 + random.nextInt(10));
                    cm.setDBUser(currentDBUser);
                    break;
                case 6: 
                    currentDBPassword = 
                        randomUtils.getRandomString(5 + random.nextInt(10));
                    cm.setDBPassword(currentDBPassword);
                    break;
            }

            assertEquals(currentIsFirewallOn, cm.getIsFirewallOn());
            assertEquals(currentIsLogActive, cm.getIsLogActive());
            assertEquals(currentActiveRuleset, cm.getActiveRuleset());
            assertEquals(currentDBIP, cm.getDBIP());
            assertEquals(currentDBName, cm.getDBName());
            assertEquals(currentDBUser, cm.getDBUser());
            assertEquals(currentDBPassword, cm.getDBPassword());
        }
    }

    // Test that the CM throws CorruptConfigurationFileException if bad file.
    public void testCorruption() 
        throws FirewallException, IOException {

        FileOutputStream fos = new FileOutputStream(testConfigFilename);
        DataOutputStream dos = new DataOutputStream(fos);
        dos.writeUTF("blah");
        dos.close();
        
        try {
            ConfigurationManager cm = 
                new ConfigurationManager(testConfigFilename);
            fail("Should've thrown CorruptConfigurationFileException!");
        } catch (CorruptConfigurationFileException e) {}
    }

    // Test that a FirewallException is thrown on IO error
    public void testFirewallException()
        throws CorruptConfigurationFileException, FirewallException, 
               IOException {

        try {
            ConfigurationManager cm = 
                new ConfigurationManager("/a/b/c/d/blah/cmtest/fw/junk.file");
            fail("Should've thrown FirewallException!");
        } catch (FirewallException e) {}
    }

	public static Test suite(String[] args) {
		if (args.length == 0) {
			return new TestSuite(ConfigurationManagerTest.class);
		} else {
			TestSuite testsToRun = new TestSuite();
			for (int i = 0; i < args.length; ++i) {
				testsToRun.addTest(new ConfigurationManagerTest(args[i]));
			}
			return testsToRun;
		}
	}
}
